home *** CD-ROM | disk | FTP | other *** search
/ Aminet 22 / Aminet 22 (1997)(GTI - Schatztruhe)[!][Dec 1997].iso / Aminet / util / misc / cookietool.lha / cookietool / cookietool.c < prev    next >
C/C++ Source or Header  |  1997-10-25  |  13KB  |  485 lines

  1. /*========================================================================*\
  2.  |  File: cookietool.c                                 Date: 25 Oct 1997  |
  3.  *------------------------------------------------------------------------*
  4.  |             Remove duplicate entries from a cookie file,               |
  5.  |                various options for sorting the output.                 |
  6.  | Expected file format is plain text with a "%%" line ending each cookie.|
  7.  |                     See help() for usage notes.                        |
  8.  |                                                                        |
  9. \*========================================================================*/
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include "strstuff.h"
  16.  
  17. char version[] = "$VER: cookietool 2.2 (25.10.97)";
  18.  
  19. struct cookie
  20.   {
  21.     UBYTE *text;
  22.     UBYTE *sorthook;
  23.     long size;
  24.     long number;
  25.   };
  26.  
  27. struct cookie *clist;
  28.  
  29. long listsize = 1000;           /* will be adjusted dynamically */
  30. long listed = 0;
  31.  
  32. #define FBUFSIZE 16384          /* we'll use larger file buffers */
  33. #define CBUFSIZE 32000L
  34. #define LBUFSIZE 2000
  35. UBYTE cbuf[ CBUFSIZE ];         /* large enough to hold one complete cookie */
  36. UBYTE line[ LBUFSIZE ];         /* large enough to hold the longest line */
  37.  
  38.  
  39.  
  40. /* 
  41.  * Print a help text and nag about illegal parameter <s> 
  42.  */
  43. void help( UBYTE *s )
  44. {
  45.   if( s )
  46.     printf( "illegal option '%s'\n", s );
  47.   printf( "usage:  cookietool [ options ] <database> \n" );
  48.   printf( "where options are:\n" );
  49.   printf( " -p      passive, don't delete anything\n" );
  50.   printf( " -a      treat 'abbreviations' as doubles (i.e. delete them, too)\n" );
  51.   printf( " -s      sort cookies\n" );
  52.   printf( " -sl      \" , looking at the last line only\n" );
  53.   printf( " -sw      \" , looking at the last word only\n" );
  54.   printf( " -s<sep>  \" , starting after the last <sep>, e.g. '-s--'\n" );
  55.   printf( " -ss      \" , by size\n" );
  56.   printf( " -d[ 0-3 ] how fussy about word delimiters? (default: 2)\n" );
  57.   printf( " -c      case sensitive comparisons\n" );
  58.   printf( " -o      overwrite directly, no tempfile (caution!)\n" );
  59. }
  60.  
  61.     
  62.  
  63. int cookie_cmp( struct cookie *a, struct cookie *b, int mode )
  64. {
  65.   int c = 0;
  66.  
  67.   switch( mode )
  68.     {
  69.     case 0:                     /* by number */
  70.       c = a->number - b->number;
  71.       break;
  72.     case 1: case -1:            /* by name, ascending/descending */
  73.       c = str_cmp( a->sorthook, b->sorthook );
  74.       if( c == 0 )              /* when in doubt, the number decides */
  75.         c = a->number - b->number;
  76.       c *= mode;            
  77.       break;
  78.     case 2:                     /* by size */
  79.       c = a->size - b->size;
  80.       break;
  81.     }
  82.   return c;
  83. }
  84.  
  85.  
  86.  
  87. /* 
  88.  * sift: centre routine to heapsort()
  89.  */
  90. void sift( struct cookie v[], long i, long m, int mode )
  91. {
  92.   long j;
  93.   struct cookie temp;
  94.  
  95.   while( (j = 2 * (i + 1) - 1) <= m )
  96.     {
  97.       if( j < m && cookie_cmp( &v[ j ], &v[ j + 1 ], mode ) < 0 )
  98.         j++;
  99.       if( cookie_cmp( &v[ i ], &v[ j ], mode ) < 0 )
  100.         {
  101.           temp = v[ i ];
  102.           v[ i ] = v[ j ];
  103.           v[ j ] = temp;
  104.           i = j;
  105.         }
  106.       else
  107.         i = m;              /* done */
  108.     }
  109. }
  110.  
  111.  
  112. void my_heapsort( struct cookie v[], long n, int mode )
  113. {
  114.   long i;
  115.   struct cookie temp;
  116.  
  117.   if( n < 2 )                   /* no sorting necessary */
  118.     return;
  119.   for( i = n/2 - 1; i >= 0; i-- )
  120.     sift( v, i, n - 1, mode );
  121.   for( i = n - 1; i >= 1; i-- )
  122.     {
  123.       temp = v[ 0 ];
  124.       v[ 0 ] = v[ i ];
  125.       v[ i ] = temp;
  126.       sift( v, 0, i - 1, mode );
  127.     }
  128. }
  129.  
  130.  
  131. UBYTE hooktarget[ 16 ];
  132.  
  133. void set_hooks( int mode )
  134. /* adjust sorthooks for the final sort, according to the desired mode */
  135. {
  136.   long l;
  137.   int hot;
  138.   UBYTE *s;
  139.  
  140.   printf( "Adjusting sort hooks" );
  141.   fflush( stdout );
  142.   for( l = 0; l < listed; l++ )
  143.     {
  144.       s = clist[ l ].text;
  145.       switch( mode )
  146.         {
  147.         case 3:         /* start of last line */
  148.           hot = 1;
  149.           while( *s )
  150.             {
  151.               if( *s == '\n' )
  152.                 hot = 1;
  153.               else if( hot )
  154.                 {
  155.                   clist[ l ].sorthook = s;
  156.                   hot = 0;
  157.                 }
  158.               s++;
  159.             }
  160.           break;
  161.         case 4:         /* start of last word */
  162.           hot = 1;
  163.           while( *s )
  164.             {
  165.               if( isspace( *s ) )
  166.                 hot = 1;
  167.               else if( hot )
  168.                 {
  169.                   clist[ l ].sorthook = s;
  170.                   hot = 0;
  171.                 }
  172.               s++;
  173.             }
  174.           break;
  175.         case 5:         /* at last occurence of <hooktarget> */
  176.           while( s )
  177.             {
  178.               clist[ l ].sorthook = s++;
  179.               s = strstr( s, hooktarget );
  180.             }
  181.           break;
  182.         default:
  183.         }
  184.     }
  185.   printf( ", done.\n" );
  186. }
  187.  
  188.  
  189.  
  190. /* 
  191.  * Delete cookies and log them to a file
  192.  */
  193. void one_cookie( int doubles, int abbrevs, int finalsort, FILE *fp )
  194. {
  195.   long i, j, dbl = 0, abr = 0;
  196.   int c;
  197.  
  198.   if( doubles )
  199.     {
  200.       printf( "Removing double entries" );
  201.       if( abbrevs )
  202.         printf( " + 'abbreviations'" );
  203.       fflush( stdout );
  204.       my_heapsort( clist, listed, -1 ); /* sort descending by string */
  205.       for( i = listed - 1; i > 0; i = j )
  206.         {
  207.           for( j = i - 1; j >= 0
  208.           && ( (c = str_cmp( clist[ j ].text, clist[ i ].text )) == 0
  209.             || (abbrevs && c == STR_SHORTER) ); j-- )
  210.             {
  211.               if( fp )
  212.                 if( fprintf( fp, "%s\n%%%%\n", clist[ j ].text ) <= 0 )
  213.                   {
  214.                     printf( "\nFile error, aborted !!!\n" );
  215.                     exit( 20 );
  216.                   }
  217.               free( clist[ j ].text );
  218.               clist[ j ] = clist[ --listed ];
  219.               if( c == 0 )
  220.                 dbl++;
  221.               else
  222.                 abr++;
  223.             }
  224.         }
  225.       printf( ", done. (%ld + %ld found)\n", dbl, abr );
  226.     }
  227.   if( finalsort > 0 )
  228.     {
  229.       if( finalsort > 2 )
  230.         set_hooks( finalsort );
  231.       printf( "Sorting" );
  232.       fflush( stdout );
  233.       if( finalsort == 2 )
  234.         my_heapsort( clist, listed, 2 );  /* sort by size */
  235.       else
  236.         my_heapsort( clist, listed, 1 );  /* sort ascending by string */
  237.     }                 
  238.   else
  239.     {
  240.       printf( "Restoring order" );
  241.       fflush( stdout );
  242.       my_heapsort( clist, listed, 0 );  /* sort by number */
  243.     }
  244.   printf( ", done.\n" );
  245. }
  246.  
  247.  
  248. void read_cookies( FILE *fp )
  249. {
  250.   long cbuflen, ignored = 0;
  251.   int lines;
  252.  
  253.   printf( "Reading cookies" );
  254.   fflush( stdout );
  255.   strcpy( cbuf, "" );
  256.   lines = 0;
  257.   cbuflen = 0;
  258.   while( fgets( line, LBUFSIZE, fp ) )
  259.     {
  260.       if( strncmp( line, "%%", 2 ) == 0 )
  261.         {                       /* "end of cookie"-marker */
  262.           if( lines > 0 )
  263.             {                   /* store the cookie */
  264.               /* but drop the last LF, to avoid trouble in recognizing abbrev's: */
  265.               cbuflen = strlen( cbuf );
  266.               if( cbuf[ cbuflen - 1 ] == '\n' )
  267.                 cbuf[ --cbuflen ] = '\0';
  268.               clist[ listed ].text = malloc( cbuflen + 1 );       /* mind the '\0'! */
  269.               if( clist[ listed ].text != NULL )
  270.                 {
  271.                   clist[ listed ].number = listed + ignored;
  272.                   clist[ listed ].size = cbuflen;
  273.                   strcpy( clist[ listed ].text, cbuf );
  274.                   clist[ listed ].sorthook = clist[ listed ].text;
  275.                 }
  276.               else
  277.                 {
  278.                   printf( "\nOut of memory\n" );
  279.                   exit( 20 );
  280.                 }
  281.               if( ++listed == listsize )
  282.                 {
  283.                   listsize = 3 * listsize / 2;
  284.                   clist = realloc( clist, listsize * sizeof( struct cookie ) );
  285.                   if( !clist )
  286.                     {
  287.                       printf( "\nList reallocation failed\n" );
  288.                       exit( 20 );
  289.                     }
  290.                 }
  291.             }
  292.           else
  293.             ignored++;          /* or ignore it */
  294.           /* start a new one */
  295.           strcpy( cbuf, "" );
  296.           lines = 0;
  297.           cbuflen = 0;
  298.         }
  299.       else
  300.         {
  301.           if( (cbuflen += strlen( line ) ) >= CBUFSIZE )
  302.             {
  303.               printf( "\nCookie too big( >%ld chars )\n", CBUFSIZE );
  304.               exit( 20 );
  305.             }
  306.           strcat( cbuf, line );
  307.           lines++;
  308.         }
  309.     }
  310.   printf( ", done. (%ld read, %ld empty)\n", listed, ignored );
  311. }
  312.  
  313.  
  314. /* 
  315.  * Write cookies to file, 
  316.  * also frees the allocated memory!
  317.  */
  318. void write_cookies( FILE *fp )
  319. {
  320.   long l;
  321.  
  322.   printf( "Writing cookies" );
  323.   fflush( stdout );
  324.   for( l = 0; l < listed; l++ )
  325.     {
  326.       if( fprintf( fp, "%s\n%%%%\n", clist[ l ].text ) <= 0 )
  327.         {
  328.           printf( "\nFile error, aborted !!!\n" );
  329.           exit( 20 );
  330.         }
  331.       free( clist[ l ].text );
  332.     }
  333.   printf( ", done. (%ld written)\n", listed );
  334. }
  335.  
  336.  
  337. int main( int argc, char *argv[] )
  338. {
  339.   UBYTE *s;
  340.   int dirty = 0, passive = 0, abbrevs = 0, finalsort = 0;
  341.   int case_sense = 0, bordermode = 2;
  342.   UBYTE name1[ 100 ], name2[ 100 ], name3[ 100 ];
  343.   FILE *infile, *outfile, *logfile;
  344.  
  345.   name1[ 0 ] = name2[ 0 ] = name3[ 0 ] = '\0';
  346.   if( argc < 2 )
  347.     {
  348.       help( NULL );
  349.       return 5;
  350.     }
  351.   while( --argc )
  352.     {
  353.       s = *++argv;
  354.       if( *s != '-' )
  355.         {
  356.           if( name1[ 0 ] == '\0' )
  357.             strcpy( name1, s );
  358.           else
  359.             strcpy( name3, s );
  360.         }
  361.       else
  362.         {
  363.           switch( *++s )
  364.             {
  365.             case 's':
  366.               switch( *++s )
  367.                 {
  368.                 case '\0':
  369.                   finalsort = 1;
  370.                   break;
  371.                 case 's':
  372.                   finalsort = 2;
  373.                   break;
  374.                 case 'l':
  375.                   finalsort = 3;
  376.                   break;
  377.                 case 'w':
  378.                   finalsort = 4;
  379.                   break;
  380.                 default:
  381.                   if( ispunct( *s ) )
  382.                     {
  383.                       finalsort = 5;
  384.                       strncpy( hooktarget, s, 15 );
  385.                     }
  386.                   else
  387.                     {
  388.                       help( argv[ 0 ] );
  389.                       return 5;
  390.                     }
  391.                 }
  392.               break;
  393.             case 'd':
  394.               if( isdigit( *++s ) )
  395.                 bordermode = atoi( s );
  396.               else
  397.                 {
  398.                   help( argv[ 0 ] );
  399.                   return 5;
  400.                 }
  401.               break;
  402.             case 'c':
  403.               case_sense = 1;
  404.               break;
  405.             case 'a':
  406.               abbrevs = 1;
  407.               break;
  408.             case 'p':
  409.               passive = 1;
  410.               break;
  411.             case 'o':
  412.               dirty = 1;
  413.               break;
  414.             default:
  415.               help( argv[ 0 ] );
  416.               return 5;
  417.             }
  418.         }
  419.     }
  420.   /* important, before calling anything from strstuff: */
  421.   str_setup( bordermode, case_sense );
  422.   if( name1[ 0 ] == '\0' )
  423.     {
  424.       help( NULL );
  425.       return 5;
  426.     }
  427.   if( dirty )
  428.     {
  429.       strcpy( name2, name1 );
  430.       printf( "Warning!  You have enabled direct writeback mode!\n" );
  431.       printf( "\e[2mDon't break (or crash) cookietool now, " );
  432.       printf( "or you will inevitably lose data!\e[0m\n" );
  433.     }
  434.   else
  435.     strcpy( name2, "ct_temp_crunchfile" );
  436.   printf( "CookieTool " );
  437.   print_strstat();
  438.   clist = malloc( listsize * sizeof( struct cookie ) );
  439.   if( !clist )
  440.     {
  441.       printf( "List allocation failed\n" );
  442.       return 20;
  443.     }
  444.   if( !(infile = fopen( name1, "r" ) ) )
  445.     {
  446.       printf( "Can't open %s for input!\n", name1 );
  447.       return 10;
  448.     }
  449.   setvbuf( infile, NULL, _IOFBF, FBUFSIZE );
  450.   if( name3[ 0 ] != '\0' )
  451.     {
  452.       if( !(logfile = fopen( name3, "w" ) ) )
  453.         {
  454.           printf( "Can't open %s for output!\n", name3 );
  455.           return 10;
  456.         }
  457.     }
  458.   else
  459.     logfile = NULL;
  460.   read_cookies( infile );
  461.   fclose( infile );
  462.   one_cookie( !passive, abbrevs, finalsort, logfile );
  463.   if( logfile )
  464.     fclose( logfile );
  465.   if( !(outfile = fopen( name2, "w" ) ) )
  466.     {
  467.       printf( "Can't open %s for output!\n", name2 );
  468.       return 10;
  469.     }
  470.   setvbuf( outfile, NULL, _IOFBF, FBUFSIZE );
  471.   write_cookies( outfile );
  472.   fclose( outfile );
  473.   free( clist );
  474.   if( !dirty )
  475.     {                           /* replace the input file */
  476.       if( remove( name1 ) != 0 || rename( name2, name1 ) != 0 )
  477.         {
  478.           printf( "Couldn't overwrite the input file!  Your cookies are in '%s'.\n", name2 );
  479.           return 5;
  480.         }
  481.     }
  482.   return 0;
  483. }
  484.  
  485.